干巴巴地叨逼叨了这么久,时候表演真正的技术了!
做个高端点儿的玩意吧,假如我们要做一个任务系统,这个系统可以在后台帮我们完成一大波(注意是一大波)数据的处理,那么我们自然想到,多开几个进程分开处理这些数据,同时我们不能执行了php task.php后终端挂起,万一一不小心关闭了终端都会导致任务失败,所以我们还要实现程序的daemon化。好啦,开始了!
首先,我们第一步就得将程序daemon化了!
加入我们fork出5个子进程就可以搞定这些任务,那么fork出5个子进程,同时父进程要负责这5个子进程的状态等。
  1. $child_pid = [];
  2. // 父进程安装SIGCHLD信号处理器并分发
  3. pcntl_signal( SIGCHLD, function(){
  4. // 这里注意要使用global将child_pid全局化,不然读到去数组将为空,具体原因可以自己思考下
  5. global $child_pid;
  6. // 如果子进程的数量大于0,也就说如果还有子进程存活未 退出,那么执行回收
  7. $child_pid_num = count( $child_pid );
  8. if( $child_pid_num > 0 ){
  9. // 循环子进程数组
  10. foreach( $child_pid as $pid_key => $pid_item ){
  11. $wait_result = pcntl_waitpid( $pid_item, $status, WNOHANG );
  12. // 如果子进程被成功回收了,那么一定要将其进程ID从child_pid中移除掉
  13. /*
  14. 大家是否还记得第四章php多进程初探---信号中提到循环while等待子进程被回收,出现20个0,第21个输出子进程号,所以这里foreach判断是否等于子进程号,-1 == $wait_result就不用多讲,也提到,子进程找不到了
  15. if( $wait_result == $pid_item || -1 == $wait_result ){
  16. unset( $child_pid[ $pid_key ] );
  17. }
  18. }
  19. }
  20. } );
  21. // fork出5个子进程出来,并给每个子进程重命名
  22. for( $i = 1; $i <= 5; $i++ ){
  23. $_pid = pcntl_fork();
  24. if( $_pid < 0 ){
  25. exit();
  26. } else if( 0 == $_pid ) {
  27. // 重命名子进程
  28. cli_set_process_title('php worker process');
  29. // do something ...
  30. // 啦啦啦啦啦啦啦啦啦啦,请在此处编写你的业务代码
  31. // 子进程退出执行,一定要exit,不然就不会fork出5个而是多于5个任务进程了
  32. exit();
  33. } else if( $_pid > 0 ) {
  34. // 将fork出的任务进程的进程ID保存到数组中
  35. $child_pid[] = $_pid;
  36. }
  37. }
  38. // 主进程继续循环不断派遣信号
  39. while( true ){
  40. pcntl_signal_dispatch();
  41. // 每派遣一次休眠一秒钟
  42. }